﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Configuration;
using System.Reflection;
using System.Configuration;
using System.ServiceModel.Description;

namespace App.Host
{
    /// <summary>
    /// A class that starts all hosts configured in the application configuration file.
    /// </summary>
    internal class WcfServiceHostContainer
    {
        #region Fields

        private List<ServiceHost> _hosts = new List<ServiceHost>();

        #endregion Fields

        #region Methods
        
        /// <summary>
        /// Starts all services in the application configuration file.
        /// </summary>
        internal void StartServices()
        {
            // Get the list of services to run
            ServicesConfigurationSection servicesSection = ConfigurationManager.GetSection("serviceSettings") as ServicesConfigurationSection;
            if (servicesSection == null)
            {
                throw new ConfigurationErrorsException("Failed to load 'serviceSettings' configuration section.");
            }

            foreach (ServiceConfigurationElement serviceElement in servicesSection.Services)
            {
                // Get the service host type
                Type serviceType = Type.GetType(serviceElement.ServiceType, true, true);
                if (serviceType == null)
                {
                    throw new TypeLoadException("Failed to get service type '" + serviceElement.ServiceType + "'.");
                }

                // Open the host
                OpenHost(serviceType);
            }
        }

        /// <summary>
        /// Stops all configured services.
        /// </summary>
        internal void StopServices()
        {
            foreach (ServiceHost host in _hosts)
            {
                CloseHost(host);
            }
        }

        /// <summary>
        /// Gets the hosted service names.
        /// </summary>
        /// <returns>string[] of service names</returns>
        public string[] GetHostedServiceNames()
        {
            List<string> names = new List<string>();
            foreach (ServiceHost host in _hosts)
            {
                StringBuilder svcInfo = new StringBuilder();
                svcInfo.AppendLine(host.Description.ConfigurationName);

                foreach (ServiceEndpoint endPoint in host.Description.Endpoints)
                {
                    svcInfo.AppendLine(endPoint.ListenUri.ToString());
                }

                names.Add(svcInfo.ToString());
            }
            return names.ToArray();
        }

        #endregion Methods

        #region Helper Methods

        /// <summary>
        /// Opens the host using the specified type.
        /// </summary>
        /// <param name="hostType">The host type.</param>
        private void OpenHost(Type hostType)
        {
            // Create the host
            ServiceHost host = new ServiceHost(hostType);

            // Open the host
            OpenHost(host);
        }

        /// <summary>
        /// Opens the specified host.
        /// </summary>
        /// <param name="host">The host.</param>
        private void OpenHost(ServiceHost host)
        {
            // Open the host
            host.Open();

            // Add the host to the list of opened hosts
            _hosts.Add(host);
        }

        /// <summary>
        /// Closes the specified host.
        /// </summary>
        /// <param name="host">The host.</param>
        private void CloseHost(ServiceHost host)
        {
            try
            {
                if (host != null)
                {
                    host.Close();
                }
            }
            catch
            {
                //TODO: put cleanup code here
            }
        }

        #endregion Helper Methods

    }
}
